package com.gitee.fastmybatis.core.query;

import com.gitee.fastmybatis.core.query.expression.BetweenValue;
import com.gitee.fastmybatis.core.query.expression.ValueConvert;
import com.gitee.fastmybatis.core.support.Getter;
import com.gitee.fastmybatis.core.util.ClassUtil;

import java.util.Collection;
import java.util.List;

/**
 * and 条件
 * @author thc
 */
public interface LambdaConditionAnd<T, R> {

    Condition getCondition();

    /**
     * 添加等于条件<br>
     *
     * <code>query.eq(User::getUserName, "Jim")</code>
     *
     * @param getter 方法函数
     * @param value      值
     * @return 返回Query对象
     */
    default T eq(Getter<R, ?> getter, Object value) {
        getCondition().eq(ClassUtil.getColumnName(getter), value);
        return (T) this;
    }

    /**
     * 根据表达式添加等于条件
     * <pre>
     *     query.eq(StringUtils.hasText(name), User::getUserName, name);
     *     等同于：
     *     if (StringUtils.hasText(name)) {
     *         query.eq(User::getUserName, name);
     *     }
     * </pre>
     *
     * @param expression 表达式，当为true时添加条件
     * @param getter 方法函数
     * @param value      值
     * @return 返回Query对象
     */
    default T eq(boolean expression, Getter<R, ?> getter, Object value) {
        if (expression) {
            eq(getter, value);
        }
        return (T) this;
    }

    /**
     * 添加不等于条件
     *
     * @param getter 方法函数
     * @param value      值
     * @return 返回Query对象
     */
    default T notEq(Getter<R, ?> getter, Object value) {
        getCondition().notEq(ClassUtil.getColumnName(getter), value);
        return (T) this;
    }

    /**
     * 根据表达式添加不等于条件
     *
     * @param expression 表达式，当为true时添加条件
     * @param getter 方法函数
     * @param value      值
     * @return 返回Query对象
     */
    default T notEq(boolean expression, Getter<R, ?> getter, Object value) {
        if (expression) {
            notEq(getter, value);
        }
        return (T) this;
    }

    /**
     * 添加大于条件,>
     *
     * @param getter 方法函数
     * @param value      值
     * @return 返回Query对象
     */
    default T gt(Getter<R, ?> getter, Object value) {
        getCondition().gt(ClassUtil.getColumnName(getter), value);
        return (T) this;
    }

    /**
     * 根据表达式添加大于条件,>
     *
     * @param expression 表达式，当为true时添加条件
     * @param getter 方法函数
     * @param value      值
     * @return 返回Query对象
     */
    default T gt(boolean expression, Getter<R, ?> getter, Object value) {
        if (expression) {
            gt(getter, value);
        }
        return (T) this;
    }

    /**
     * 添加大于等于条件,>=
     *
     * @param getter 方法函数
     * @param value      值
     * @return 返回Query对象
     */
    default T ge(Getter<R, ?> getter, Object value) {
        getCondition().ge(ClassUtil.getColumnName(getter), value);
        return (T) this;
    }

    /**
     * 根据表达式添加大于等于条件,>=
     *
     * @param expression 表达式，当为true时添加条件
     * @param getter 方法函数
     * @param value      值
     * @return 返回Query对象
     */
    default T ge(boolean expression, Getter<R, ?> getter, Object value) {
        if (expression) {
            ge(getter, value);
        }
        return (T) this;
    }

    /**
     * 添加小于条件,<
     *
     * @param getter 方法函数
     * @param value      值
     * @return 返回Query对象
     */
    default T lt(Getter<R, ?> getter, Object value) {
        getCondition().lt(ClassUtil.getColumnName(getter), value);
        return (T) this;
    }

    /**
     * 根据表达式添加小于条件,<
     *
     * @param expression 表达式，当为true时添加条件
     * @param getter 方法函数
     * @param value      值
     * @return 返回Query对象
     */
    default T lt(boolean expression, Getter<R, ?> getter, Object value) {
        if (expression) {
            lt(getter, value);
        }
        return (T) this;
    }

    /**
     * 小于等于,<=
     *
     * @param getter 方法函数
     * @param value      值
     * @return 返回Query对象
     */
    default T le(Getter<R, ?> getter, Object value) {
        getCondition().le(ClassUtil.getColumnName(getter), value);
        return (T) this;
    }

    /**
     * 根据表达式小于等于条件,<=
     *
     * @param expression 表达式，当为true时添加条件
     * @param getter 方法函数
     * @param value      值
     * @return 返回Query对象
     */
    default T le(boolean expression, Getter<R, ?> getter, Object value) {
        if (expression) {
            le(getter, value);
        }
        return (T) this;
    }

    /**
     * 添加两边模糊查询条件，两边模糊匹配，即name like '%value%'
     *
     * @param getter 方法函数
     * @param value      值,不需要加%
     * @return 返回Query对象
     * @see #likeLeft(Getter, String) 左边模糊匹配
     * @see #likeRight(Getter, String) 右边模糊匹配
     */
    default T like(Getter<R, ?> getter, String value) {
        getCondition().like(ClassUtil.getColumnName(getter), value);
        return (T) this;
    }

    /**
     * 根据表达式添加两边模糊查询条件，两边模糊匹配，即name like '%value%'
     *
     * @param expression 表达式，当为true时添加条件
     * @param getter 方法函数
     * @param value      值,不需要加%
     * @return 返回Query对象
     * @see #likeLeft(boolean, Getter, String) 左模糊
     * @see #likeRight(boolean, Getter, String) 右模糊
     */
    default T like(boolean expression, Getter<R, ?> getter, String value) {
        if (expression) {
            like(getter, value);
        }
        return (T) this;
    }

    /**
     * 添加左模糊查询条件，左边模糊匹配，即name like '%value'
     *
     * @param getter 方法函数
     * @param value      值,不需要加%
     * @return 返回Query对象
     */
    default T likeLeft(Getter<R, ?> getter, String value) {
        getCondition().likeLeft(ClassUtil.getColumnName(getter), value);
        return (T) this;
    }

    /**
     * 根据表达式添加左模糊查询条件，左边模糊匹配，即name like '%value'
     *
     * @param expression 表达式，当为true时添加条件
     * @param getter 方法函数
     * @param value      值,不需要加%
     * @return 返回Query对象
     */
    default T likeLeft(boolean expression, Getter<R, ?> getter, String value) {
        if (expression) {
            likeLeft(getter, value);
        }
        return (T) this;
    }

    /**
     * 添加右模糊查询条件，右边模糊匹配，即name like 'value%'。mysql推荐用这种
     *
     * @param getter 方法函数
     * @param value      值,不需要加%
     * @return 返回Query对象
     */
    default T likeRight(Getter<R, ?> getter, String value) {
        getCondition().likeRight(ClassUtil.getColumnName(getter), value);
        return (T) this;
    }

    /**
     * 根据表达式添加右模糊查询条件，右边模糊匹配，即name like 'value%'。mysql推荐用这种
     *
     * @param expression 表达式，当为true时添加条件
     * @param getter 方法函数
     * @param value      值,不需要加%
     * @return 返回Query对象
     */
    default T likeRight(boolean expression, Getter<R, ?> getter, String value) {
        if (expression) {
            likeRight(getter, value);
        }
        return (T) this;
    }

    /**
     * 添加IN条件
     *
     * @param getter 方法函数
     * @param value      值
     * @return 返回Query对象
     */
    default T in(Getter<R, ?> getter, Collection<?> value) {
        getCondition().in(ClassUtil.getColumnName(getter), value);
        return (T) this;
    }

    /**
     * 根据表达式添加IN条件
     *
     * @param expression 表达式，当为true时添加条件
     * @param getter 方法函数
     * @param value      值
     * @return 返回Query对象
     */
    default T in(boolean expression, Getter<R, ?> getter, Collection<?> value) {
        if (expression) {
            in(getter, value);
        }
        return (T) this;
    }

    /**
     * 添加IN条件
     *
     * @param getter   数据库字段名
     * @param value        值
     * @param valueConvert 转换
     * @return 返回Query对象
     */
    default <E> T in(Getter<R, ?> getter, Collection<E> value, ValueConvert<E> valueConvert) {
        getCondition().in(ClassUtil.getColumnName(getter), value, valueConvert);
        return (T) this;
    }

    /**
     * 根据表达式添加IN条件
     *
     * @param expression   表达式，当为true时添加条件
     * @param getter   数据库字段名
     * @param value        值
     * @param valueConvert 转换
     * @return 返回Query对象
     */
    default <E> T in(boolean expression, Getter<R, ?> getter, Collection<E> value, ValueConvert<E> valueConvert) {
        if (expression) {
            in(getter, value, valueConvert);
        }
        return (T) this;
    }

    /**
     * 添加IN条件
     *
     * @param getter 方法函数
     * @param value      值
     * @return 返回Query对象
     */
    default T in(Getter<R, ?> getter, Object[] value) {
        getCondition().in(ClassUtil.getColumnName(getter), value);
        return (T) this;
    }

    /**
     * 根据表达式添加IN条件
     *
     * @param expression 表达式，当为true时添加条件
     * @param getter 方法函数
     * @param value      值
     * @return 返回Query对象
     */
    default T in(boolean expression, Getter<R, ?> getter, Object[] value) {
        if (expression) {
            in(getter, value);
        }
        return (T) this;
    }

    /**
     * 添加not in条件
     *
     * @param getter 方法函数
     * @param value      值
     * @return 返回Query对象
     */
    default T notIn(Getter<R, ?> getter, Collection<?> value) {
        getCondition().notIn(ClassUtil.getColumnName(getter), value);
        return (T) this;
    }

    /**
     * 根据表达式添加not in条件
     *
     * @param expression 表达式，当为true时添加条件
     * @param getter 方法函数
     * @param value      值
     * @return 返回Query对象
     */
    default T notIn(boolean expression, Getter<R, ?> getter, Collection<?> value) {
        if (expression) {
            notIn(getter, value);
        }
        return (T) this;
    }

    /**
     * 添加not in条件
     *
     * @param getter   数据库字段名
     * @param value        值
     * @param valueConvert 转换器
     * @return 返回Query对象
     */
    default <E> T notIn(Getter<R, ?> getter, Collection<E> value, ValueConvert<E> valueConvert) {
        getCondition().notIn(ClassUtil.getColumnName(getter), value, valueConvert);
        return (T) this;
    }

    /**
     * 根据表达式添加not in条件
     *
     * @param expression   表达式，当为true时添加条件
     * @param getter   数据库字段名
     * @param value        值
     * @param valueConvert 转换器
     * @return 返回Query对象
     */
    default <E> T notIn(boolean expression, Getter<R, ?> getter, Collection<E> value, ValueConvert<E> valueConvert) {
        if (expression) {
            notIn(getter, value, valueConvert);
        }
        return (T) this;
    }

    /**
     * 添加not in条件
     *
     * @param getter 方法函数
     * @param value      值
     * @return 返回Query对象
     */
    default T notIn(Getter<R, ?> getter, Object[] value) {
        getCondition().notIn(ClassUtil.getColumnName(getter), value);
        return (T) this;
    }

    /**
     * 根据表达式添加not in条件
     *
     * @param expression 表达式，当为true时添加条件
     * @param getter 方法函数
     * @param value      值
     * @return 返回Query对象
     */
    default T notIn(boolean expression, Getter<R, ?> getter, Object[] value) {
        if (expression) {
            notIn(getter, value);
        }
        return (T) this;
    }

    /**
     * 添加between条件
     *
     * @param getter 方法函数
     * @param startValue 起始值
     * @param endValue   结束值
     * @return 返回Query对象
     */
    default T between(Getter<R, ?> getter, Object startValue, Object endValue) {
        getCondition().between(ClassUtil.getColumnName(getter), startValue, endValue);
        return (T) this;
    }

    /**
     * 添加between条件
     *
     * @param expression 表达式，当为true时添加条件
     * @param getter 方法函数
     * @param startValue 起始值
     * @param endValue   结束值
     * @return 返回Query对象
     */
    default T between(boolean expression, Getter<R, ?> getter, Object startValue, Object endValue) {
        if (expression) {
            between(getter, startValue, endValue);
        }
        return (T) this;
    }

    /**
     * 添加between条件
     * <pre>
     * {@literal
     * Object[] arr = new Object[]{1, 100};
     * query.between(arr);
     * }
     * </pre>
     *
     * @param values 存放起始值、结束值，只能存放2个值，values[0]表示开始值，value[1]表示结束值
     * @return 返回Query对象
     */
    default T between(Getter<R, ?> getter, Object[] values) {
        getCondition().between(ClassUtil.getColumnName(getter), values);
        return (T) this;
    }

    /**
     * 添加between条件
     *
     * @param expression 表达式，当为true时添加条件
     * @param getter 方法函数
     * @param values     存放起始值、结束值，只能存放2个值，values[0]表示开始值，value[1]表示结束值
     * @return 返回Query对象
     */
    default T between(boolean expression, Getter<R, ?> getter, Object[] values) {
        if (expression) {
            between(getter, values);
        }
        return (T) this;
    }

    /**
     * 添加between条件
     * <pre>
     * {@literal
     * query.between(Arrays.asList(1, 100));
     * }
     * </pre>
     *
     * @param values 存放起始值、结束值，只能存放2个值
     * @return 返回Query对象
     */
    default T between(Getter<R, ?> getter, List<?> values) {
        getCondition().between(ClassUtil.getColumnName(getter), values);
        return (T) this;
    }

    /**
     * 添加between条件
     *
     * @param expression 表达式，当为true时添加条件
     * @param getter 方法函数
     * @param values     存放起始值、结束值，只能存放2个值
     * @return 返回Query对象
     */
    default T between(boolean expression, Getter<R, ?> getter, List<?> values) {
        if (expression) {
            between(getter, values);
        }
        return (T) this;
    }

    /**
     * 添加between条件
     * <pre>
     * {@literal
     * query.between(new BetweenValue(1, 100));
     * }
     * </pre>
     *
     * @param betweenValue 起始值、结束值包装对象
     * @return 返回Query对象
     */
    default T between(Getter<R, ?> getter, BetweenValue betweenValue) {
        getCondition().between(ClassUtil.getColumnName(getter), betweenValue);
        return (T) this;
    }

    /**
     * 添加between条件
     *
     * @param expression   表达式，当为true时添加条件
     * @param getter   数据库字段名
     * @param betweenValue 存放起始值、结束值，只能存放2个值
     * @return 返回Query对象
     */
    default T between(boolean expression, Getter<R, ?> getter, BetweenValue betweenValue) {
        if (expression) {
            between(getter, betweenValue);
        }
        return (T) this;
    }




    /**
     * 添加字段不为null的条件
     *
     * @param getter 方法函数
     * @return 返回Query对象
     */
    default T notNull(Getter<R, ?> getter) {
        this.getCondition().sql(ClassUtil.getColumnName(getter) + " IS NOT NULL");
        return (T) this;
    }

    /**
     * 根据表达式添加字段不为null的条件
     *
     * @param expression 表达式，当为true时添加条件
     * @param getter 方法函数
     * @return 返回Query对象
     */
    default T notNull(boolean expression, Getter<R, ?> getter) {
        if (expression) {
            notNull(getter);
        }
        return (T) this;
    }

    /**
     * 添加字段是null的条件
     *
     * @param getter 方法函数
     * @return 返回Query对象
     */
    default T isNull(Getter<R, ?> getter) {
        this.getCondition().sql(ClassUtil.getColumnName(getter) + " IS NULL");
        return (T) this;
    }

    /**
     * 根据表达式添加字段是null的条件
     *
     * @param expression 表达式，当为true时添加条件
     * @param getter 方法函数
     * @return 返回Query对象
     */
    default T isNull(boolean expression, Getter<R, ?> getter) {
        if (expression) {
            isNull(getter);
        }
        return (T) this;
    }

    /**
     * 添加不为空字符串条件
     *
     * @param getter 方法函数
     * @return 返回Query对象
     */
    default T notEmpty(Getter<R, ?> getter) {
        String column = ClassUtil.getColumnName(getter);
        this.getCondition().sql(column + " IS NOT NULL AND " + column + " <> '' ");
        return (T) this;
    }

    /**
     * 根据表达式添加不为空字符串条件
     *
     * @param expression 表达式，当为true时添加条件
     * @param getter 方法函数
     * @return 返回Query对象
     */
    default T notEmpty(boolean expression, Getter<R, ?> getter) {
        if (expression) {
            notEmpty(getter);
        }
        return (T) this;
    }

    /**
     * 添加空字段条件，null或者空字符串
     *
     * @param getter 方法函数
     * @return 返回Query对象
     */
    default T isEmpty(Getter<R, ?> getter) {
        String column = ClassUtil.getColumnName(getter);
        this.getCondition().sql(column + " IS NULL OR " + column + " = '' ");
        return (T) this;
    }

    /**
     * 根据表达式添加空字段条件，null或者空字符串
     *
     * @param expression 表达式，当为true时添加条件
     * @param getter 方法函数
     * @return 返回Query对象
     */
    default T isEmpty(boolean expression, Getter<R, ?> getter) {
        if (expression) {
            isEmpty(getter);
        }
        return (T) this;
    }

}
